﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace PlusPlusPaint.FileIO
{
    /// <summary>
    /// Reads symbols from the input and return tokens one by one.
    /// </summary>
    class LayeredDataLexer
    {
        #region member variables
        string currentInput;
        readonly IDictionary<Tokens, Regex> tokenFootprints = new Dictionary<Tokens, Regex>();

        #endregion

        #region properties
        public string Input
        {
            get
            {
                return this.currentInput;
            }
            set
            {
                this.currentInput = value.Trim();
            }
        }
        #endregion

        #region constructors
        public LayeredDataLexer(string input = "")
        {
            this.currentInput = input.Trim();
            this.initializeTokenFootprints();
        }
        #endregion

        #region public methods
        public Token RetrieveNextToken()
        {
            currentInput = currentInput.TrimStart();
            if (currentInput == "")
                return new Token(Tokens.EndOfFile, "");

            foreach (Tokens type in Enum.GetValues(typeof(Tokens)))
            {
                Match match = this.tokenFootprints[type].Match(this.currentInput);
                if (!match.Success)
                    continue;
                this.currentInput = this.currentInput.Substring(match.Length); // Scrap the beginning
                return new Token(type, match.Value.Trim());
            }

            string badtoken = currentInput.Substring(0, currentInput.IndexOf(' '));
            throw new Exception("Lexer error:  Unknown token \"" + badtoken + "\".");
        }

        public static string SerializeString(string str)
        {
            if (str == null)
                return "\"\"";
            // Get rid of control characters
            str = str.Replace("\r\n", "\\n");
            str = str.Replace("\"", "\\\"");
            // Add quotes
            return "\"" + str + "\"";
        }

        public static string DeserializeString(string str)
        {
            // Need to remove the quotes
            str = str.Substring(1, str.Length - 2);
            // Getting rid of control characters
            str = str.Replace("\\n", "\r\n");
            str = str.Replace("\\\"", "\"");
            return str;
        }
        #endregion

        #region private methods
        private void initializeTokenFootprints()
        {
            tokenFootprints[Tokens.BeginDocument] = new Regex("^<<<");
            tokenFootprints[Tokens.ClosingParen] = new Regex("^\\)");
            tokenFootprints[Tokens.Colon] = new Regex("^:");
            tokenFootprints[Tokens.EndDocument] = new Regex("^>>>");
            tokenFootprints[Tokens.EndOfFile] = new Regex("^$");
            tokenFootprints[Tokens.Identifier] = new Regex("^[a-zA-Z_]+");
            tokenFootprints[Tokens.Integer] = new Regex("^(\\+|-)?([0-9]+|0x[0-9A-Fa-f]+)");
            tokenFootprints[Tokens.OpeningParen] = new Regex("^\\(");
            tokenFootprints[Tokens.String] = new Regex("^\"([^\"\\\\]|\\\\.)*\""); // Thanks http://wordaligned.org/articles/string-literals-and-regular-expressions
        }
        #endregion
    }
}
